﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using GameTimeSystem;

namespace CameraSystem
{
    public class CameraItem
    {



        private Vector2 shakeDir=Vector2.zero;

        Camera targetCamera;

        public Transform CameraTrans { get { return targetCamera.transform; } }

        Dictionary<CameraEffectType, CameraEffectBase> cameraEffects = new Dictionary<CameraEffectType, CameraEffectBase>();
        public CameraItem(Camera camera)
        {
            targetCamera = camera;
        }

        #region 相机视线被阻挡时透明化
        private bool isFadeObject;
        public bool IsFadeObject
        {
            set
            {
                isFadeObject = value;
                if (isFadeObject)
                {
                    GameTimer timer = GameTimeSystemFacade.Inst.GetGameUpdateTimer(SystemPriority.Camera);
                    timer.Register(CheckFadeObjectEnd, OnFadeObjectUpdate);
                }
            }
            get { return isFadeObject; }
        }

        public float FadeObjAlpha { get; set; }

        private GameObject preHitObj;

        void OnFadeObjectUpdate(float deltaTime)
        {
            Ray ray = new Ray(targetCamera.transform.position, (FocusTarget.transform.position - targetCamera.transform.position).normalized);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, (FocusTarget.transform.position - targetCamera.transform.position).magnitude))
            {
                GameObject hitObj = hit.collider.gameObject;
                if (preHitObj != null)
                {
                    preHitObj.GetComponent<Renderer>().material.color = new Color(1, 1, 1, 1);
                }
                if (hitObj.GetComponent<Renderer>() != null)
                {
                    preHitObj = hitObj;
                    preHitObj.GetComponent<Renderer>().material.color = new Color(1, 1, 1, FadeObjAlpha);
                }
            }
        }

        bool CheckFadeObjectEnd()
        {
            return !isFadeObject;
        }
        #endregion

        #region 屏幕震动

        Vector3 originPos;
        float ShakeStep;
        float ShakeSpeed;
        GameTimer ShakeTimer;
        Action onShakeFinished;

        /// <summary>
        /// 震动
        /// </summary>
        /// <param name="shakeTime">震动持续时间</param>
        /// <param name="shakeStep">震动步长</param>
        /// <param name="shakeSpeed">震动速度</param>
        public void Shake(float shakeTime = 0.5f, float shakeStep = 5, float shakeSpeed = 0.5f,Action onFinish=null)
        {
            ShakeStep = shakeStep;
            ShakeSpeed = Mathf.Clamp(shakeSpeed, 0, 1);
            if (ShakeTimer != null)
            {
                return;
            }
            ShakeTimer = GameTimeSystemFacade.Inst.GetGameUpdateTimer(SystemPriority.Camera);
            originPos = targetCamera.transform.localPosition;
            onShakeFinished = onFinish;
            ShakeTimer.Register(shakeTime, OnShakeUpdate, OnShakeCompleted);
        }

        void OnShakeUpdate(float deltaTime)
        {
            Vector3 RandomPoint = originPos + UnityEngine.Random.insideUnitSphere * ShakeStep;
            targetCamera.transform.localPosition = Vector3.Lerp(targetCamera.transform.localPosition, RandomPoint, Time.deltaTime * ShakeSpeed);
        }

        void OnShakeCompleted()
        {
            targetCamera.transform.localPosition = originPos;
            ShakeTimer = null;
            if (onShakeFinished!=null)
            {
                onShakeFinished();
            }
        }

        #endregion

        #region 聚焦物相关
        public GameObject FocusTarget { get; set; }
        private GameObject PredictPoint;
        /// <summary>预测旋转最后结果的点 </summary>
        private GameObject PredictEndPoint;
        private GameObject CameraRootRight;
        private GameObject CameraRootUp;


        #region 绕聚焦物旋转
        GameTimer rotateGameTimer;
        /// <summary>绕右轴的旋转角 </summary>
        float targetAngleWithRight;
        /// <summary>绕上轴的旋转角 </summary>
        float targetAngleWithUp;
        float rotateSpeed;
        float maxRightRotateStep = 1;
        float maxUpRotateStep = 5;

        bool isRotate;
        bool isAsyncRotate;

        public void SetMaxStep(float maxRightRotateStep,float maxUpRotateStep)
        {
            this.maxRightRotateStep = maxRightRotateStep;
            this.maxUpRotateStep = maxUpRotateStep;
        }

        public void RotateWithFocusTarget(float angleWithUp, float angleWithRight, float speed, bool isAsync = false)
        {
            if (FocusTarget==null)
            {
                Debug.LogError("FocusTarget is null!!");
                return;
            }
            if (CameraRootRight == null)
            {
                CameraRootUp = new GameObject("CameraRootUp");
                CameraRootUp.transform.parent = targetCamera.transform.parent;
                CameraRootUp.transform.eulerAngles = targetCamera.transform.parent.eulerAngles;
                CameraRootUp.transform.position = targetCamera.transform.parent.position;

                CameraRootRight = new GameObject("CameraRootRight");
                CameraRootRight.transform.parent = CameraRootUp.transform;
                CameraRootRight.transform.eulerAngles = CameraRootUp.transform.parent.eulerAngles;
                CameraRootRight.transform.position = CameraRootUp.transform.parent.position;

                targetCamera.transform.parent = CameraRootRight.transform;

                PredictPoint = new GameObject("PredictPoint");
                PredictPoint.transform.parent = targetCamera.transform.parent;
                PredictPoint.transform.eulerAngles = targetCamera.transform.parent.eulerAngles;
                PredictPoint.transform.position = targetCamera.transform.parent.position;
                PredictPoint.transform.parent = CameraRootRight.transform;

                PredictEndPoint = new GameObject("PredictEndPoint");
                PredictEndPoint.transform.parent = targetCamera.transform.parent;
                PredictEndPoint.transform.eulerAngles = targetCamera.transform.parent.eulerAngles;
                PredictEndPoint.transform.position = targetCamera.transform.parent.position;
                PredictEndPoint.transform.parent = CameraRootRight.transform;
            }

            targetAngleWithUp = angleWithUp;
            targetAngleWithRight = angleWithRight;
            rotateSpeed = speed;
            isAsyncRotate = isAsync;
            //targetCamera.transform.LookAt(FocusTarget.transform);
            if (isAsync)
            {
                rotateGameTimer= GameTimeSystemFacade.Inst.GetGameUpdateTimer(SystemPriority.Camera, false);
                rotateGameTimer.Register(CheckRotateEnd,OnRotateUpdate, OnComplete);
            }
            else
            {
                if (rotateGameTimer == null)
                {
                    rotateGameTimer = GameTimeSystemFacade.Inst.GetGameUpdateTimer(SystemPriority.Camera, true);
                    rotateGameTimer.Register(OnRotateUpdate);
                }
            }

            PredictEndPoint.transform.eulerAngles = targetCamera.transform.eulerAngles;
            PredictEndPoint.transform.position = targetCamera.transform.position;
            PredictEndPoint.transform.RotateAround(FocusTarget.transform.position, targetCamera.transform.right, targetAngleWithRight);
            PredictEndPoint.transform.RotateAround(FocusTarget.transform.position, FocusTarget.transform.up, targetAngleWithUp);
            isRotate = true;
        }

        bool CheckRotateEnd()
        {
            if (Vector3.Distance(PredictEndPoint.transform.position, targetCamera.transform.position) < 0.1)
            {
                return true;
            }
            return false;
        }

        void OnComplete()
        {
            rotateGameTimer = null;
        }

        void OnRotateUpdate(float deltaTime)
        {
            if (!isAsyncRotate)
            {
                if (!isRotate)
                {
                    return;
                }
                else
                {
                    isRotate = false;
                }
            }
            targetAngleWithRight = Mathf.Clamp(targetAngleWithRight * rotateSpeed, -maxRightRotateStep, maxRightRotateStep);
            targetAngleWithUp = Mathf.Clamp(targetAngleWithUp * rotateSpeed, -maxUpRotateStep, maxUpRotateStep);
            PredictPoint.transform.RotateAround(FocusTarget.transform.position, targetCamera.transform.right, targetAngleWithRight);

            if (PredictPoint.transform.eulerAngles.x > 10 && PredictPoint.transform.eulerAngles.x < 50)
            {
                CameraRootRight.transform.RotateAround(FocusTarget.transform.position, targetCamera.transform.right, targetAngleWithRight);
            }
            CameraRootUp.transform.RotateAround(FocusTarget.transform.position, FocusTarget.transform.up, targetAngleWithUp);
            PredictPoint.transform.eulerAngles = targetCamera.transform.eulerAngles;
        }


        #endregion

        #region 跟随聚焦物

        public void FollowFocusTarget()
        {

        }

        #endregion
        #endregion

        #region 屏幕渲染
        public void ShowCameraEffect(CameraEffectType effectType,params object[] args)
        {
            Type cameraEffectType= CameraSystemFacade.Inst.GetCameraEffectType(effectType);
            if (!cameraEffects.ContainsKey(effectType))
            {
                CameraEffectBase effect = (CameraEffectBase) targetCamera.gameObject.AddComponent(cameraEffectType);
                cameraEffects.Add(effectType, effect);
            }
            cameraEffects[effectType].SetArgs(args);
        }

        public void HideCameraEffect(CameraEffectType effectType)
        {
            Type cameraEffectType = CameraSystemFacade.Inst.GetCameraEffectType(effectType);
            Component effect = targetCamera.GetComponent(cameraEffectType);
            if (effect == null)
            {
                Debug.LogError("当前相机无此特效组件，无需隐藏");
                return;
            }
        }

        #endregion

        public void ScaleTo()
        {

        }


    }
}
